/*
 * Copyright (c) 2021 Huawei Device Co., Ltd.
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package com.huawei.healthecology.processor;

import com.huawei.healthecology.api.WifiCentral;
import com.huawei.healthecology.data.wifi.data.WifiBand;
import com.huawei.healthecology.data.wifi.data.WifiBandWidth;
import com.huawei.healthecology.data.wifi.data.WifiConnectedInfo;
import com.huawei.healthecology.data.wifi.data.WifiScannedInfo;
import com.huawei.healthecology.data.wifi.response.WifiConnectionResponse;
import com.huawei.healthecology.data.wifi.response.WifiResponseCode;
import com.huawei.healthecology.data.wifi.response.WifiScanningResponse;
import com.huawei.healthecology.data.wifi.response.WifiStatusResponse;

import lombok.Builder;
import ohos.app.Context;
import ohos.wifi.WifiDevice;

import org.jetbrains.annotations.NotNull;

import java.util.Optional;
import java.util.stream.Collectors;

/**
 * Wifi device processor
 */
public class WifiDeviceProcessor implements WifiCentral, HealthEcologyProcessor {
    private static final String TAG = "WifiDeviceProcessor";

    private final Context contextInstance;

    private WifiDevice wifiDevice;

    /**
     * constructor
     *
     * @param context context
     */
    @Builder(builderMethodName = "hiddenBuilder")
    public WifiDeviceProcessor(@NotNull Context context) {
        this.contextInstance = context;
    }

    /**
     * WifiDeviceProcessor Builder
     *
     * @param context context
     * @return WifiDeviceProcessor
     */
    public static WifiDeviceProcessorBuilder builder(Context context) {
        return hiddenBuilder().context(context);
    }

    @Override
    public void initProcessor() {
        this.wifiDevice = WifiDevice.getInstance(contextInstance);
    }

    @Override
    public void releaseResource() {
    }

    @Override
    public void destroyProcessor() {
        wifiDevice = null;
    }

    @Override
    public WifiResponseCode startScanning() {
        return Optional.ofNullable(wifiDevice)
            .map(WifiDevice::scan)
            .map(result -> result
                ? WifiResponseCode.OPERATION_SUCCESS
                : WifiResponseCode.SYSTEM_ERROR)
            .orElse(WifiResponseCode.NOT_INITIALIZED);
    }

    @Override
    public WifiStatusResponse getWifiStatus() {
        return Optional.ofNullable(wifiDevice)
            .map(device -> WifiStatusResponse.builder()
                .responseCode(WifiResponseCode.OPERATION_SUCCESS)
                .isAvailable(device.isWifiActive())
                .isConnected(device.isConnected())
                .build())
            .orElse(WifiStatusResponse.builder()
                .responseCode(WifiResponseCode.NOT_INITIALIZED)
                .build());
    }

    @Override
    public WifiConnectionResponse getConnectedInformation() {
        return Optional.ofNullable(wifiDevice)
            .flatMap(WifiDevice::getLinkedInfo)
            .map(linkedInfo -> WifiConnectionResponse.builder()
                .responseCode(WifiResponseCode.OPERATION_SUCCESS)
                .information(WifiConnectedInfo.of(linkedInfo.getSsid(),
                    linkedInfo.getBssid(),
                    linkedInfo.getConnState().name()))
                .build())
            .orElse(WifiConnectionResponse.builder()
                .responseCode(WifiResponseCode.OPERATION_FAILED).build());
    }

    @Override
    public WifiScanningResponse getScannedInformation() {
        return Optional.ofNullable(wifiDevice)
            .map(device -> device.getScanInfoList().stream())
            .map(infoStream -> infoStream
                .map(wifiScanInfo -> WifiScannedInfo.of(wifiScanInfo.getSsid(),
                    wifiScanInfo.getBssid(),
                    wifiScanInfo.getCapabilities(),
                    WifiBand.parseTo(wifiScanInfo.getBand()).name(),
                    WifiBandWidth.parseTo(wifiScanInfo.getBandWidth()).name()))
                .collect(Collectors.toList()))
            .map(wifiInformationList -> WifiScanningResponse.builder()
                .responseCode(WifiResponseCode.OPERATION_SUCCESS)
                .informationList(wifiInformationList)
                .build())
            .orElse(WifiScanningResponse.builder()
                .responseCode(WifiResponseCode.INTERNAL_ERROR)
                .build());
    }
}
